package com.yonyou.pmclouds.plan.processor;

import com.yonyou.pmclouds.basecom.bp.processor.SingleProcessor;
import com.yonyou.pmclouds.basecom.exception.BusinessException;
import com.yonyou.pmclouds.basecom.util.DateUtils;
import com.yonyou.pmclouds.plan.entity.ProjectPlanVO;
import com.yonyou.pmclouds.plan.mapper.ProjectPlanMapper;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class PlanAdjustUpperProcessor implements SingleProcessor<ProjectPlanVO> {
    private ProjectPlanVO parent;
    private ProjectPlanMapper mapper;

    public PlanAdjustUpperProcessor(ProjectPlanVO parent, ProjectPlanMapper mapper) {
        this.parent = parent;
        this.mapper = mapper;
    }

    @Override
    public void process(ProjectPlanVO vo, ProjectPlanVO orig) throws BusinessException {
        // 调整每层上级的开始日期、结束日期
        boolean insert = orig == null;
        if (StringUtils.isEmpty(vo.getPkParent())) {
            return;
        }
        ProjectPlanVO upper = parent;
        ProjectPlanVO oriUpper = (ProjectPlanVO) parent.clone();
        List<ProjectPlanVO> updatePlan = new ArrayList<>();
        if (insert) {
            fetchUpdateForInsert(vo, upper, updatePlan);
        } else {
            fetchUpdateForUpdate(vo, upper, orig, oriUpper, updatePlan);
        }
        for (ProjectPlanVO plan : updatePlan) {
            mapper.updateFields(plan, new String[]{ProjectPlanVO.EXPE_START_DATE, ProjectPlanVO.EXPE_END_DATE, ProjectPlanVO.EXPE_DURATION});
        }
    }

    public void processDelete(ProjectPlanVO deleted) {
        String parentId = deleted.getPkParent();
        if (StringUtils.isEmpty(parentId)) {
            return;
        }
        ProjectPlanVO parent = mapper.getById(parentId);
        if (parent == null) {
            return;
        }
        Date start = mapper.earliestDateOfParentExpectSpecialChild(parentId, null);
        Date end = mapper.latestDateOfParentExpectSpecialChild(parentId, null);
        ProjectPlanVO orig = (ProjectPlanVO) parent.clone();
        // 如果没有下级了，或者时间没有发生改变，则不需要更新
        // 开始日期结束日期一定同时为空
        if (start == null || end == null
                || (start.equals(parent.getExpeStartDate()) && end.equals(parent.getExpeEndDate()))) {
            return;
        }
        parent.setExpeStartDate(start);
        parent.setExpeEndDate(end);
        parent.setExpeDuration((int) DateUtils.getDaysBetween(start, end));
        List<ProjectPlanVO> updatePlan = new ArrayList<>();
        updatePlan.add(parent);
        if (!StringUtils.isEmpty(parent.getPkParent())) {
            ProjectPlanVO grand = mapper.getById(parent.getPkParent());
            if (grand != null) {
                fetchUpdateForUpdate(parent, grand, orig, (ProjectPlanVO) grand.clone(), updatePlan);
            }
        }
        for (ProjectPlanVO plan : updatePlan) {
            mapper.updateFields(plan, new String[]{ProjectPlanVO.EXPE_START_DATE, ProjectPlanVO.EXPE_END_DATE, ProjectPlanVO.EXPE_DURATION});
        }
    }

    private void fetchUpdateForUpdate(ProjectPlanVO cur, ProjectPlanVO upper, ProjectPlanVO ori, ProjectPlanVO oriUpper, List<ProjectPlanVO> updatePlan) {
        //  更新时，如果时间范围变小，需要查询同级，重新合并时间范围
        boolean needUpper = false;
        do {
            needUpper = false;
            Date start = cur.getExpeStartDate();
            Date end = cur.getExpeEndDate();
            Date upStart = upper.getExpeStartDate();
            Date upEnd = upper.getExpeEndDate();
            Date oriStart = ori.getExpeStartDate();
            Date oriEnd = ori.getExpeEndDate();
            if (start.compareTo(upStart) < 0) {
                upStart = start;
                upper.setExpeStartDate(upStart);
                needUpper = true;
            } else if (start.compareTo(upStart) > 0) {
                //  和原始日期比较
                // 相等才能说明上级的时间范围可能由该计划确定，不等的话，与该计划无关
                if (oriStart.equals(upStart)) {
                    Date d = mapper.earliestDateOfParentExpectSpecialChild(upper.getPkPlan(), cur.getPkPlan());
                    // 数据库查询结果可空, 原始值和上级值不等，同时又只有一个下级的情况不存子啊，应该不会走到这里
                    if (d == null || start.compareTo(d) < 0) {
                        upStart = start;
                        upper.setExpeStartDate(upStart);
                        needUpper = true;
                    } else if (start.compareTo(d) > 0) {
                        upStart = d;
                        upper.setExpeStartDate(upStart);
                        needUpper = true;

                    }
                }
            }
            if (end.compareTo(upEnd) > 0) {
                upEnd = end;
                upper.setExpeEndDate(upEnd);
                needUpper = true;
            } else if (end.compareTo(upEnd) < 0) {
                // 相等才能说明上级的时间范围可能由该计划确定，不等的话，与该计划无关
                if (oriEnd.equals(upEnd)) {
                    Date d = mapper.latestDateOfParentExpectSpecialChild(upper.getPkPlan(), cur.getPkPlan());
                    if (d == null || end.compareTo(d) > 0) {
                        upEnd = end;
                        upper.setExpeEndDate(upEnd);
                        needUpper = true;
                    } else if (end.compareTo(d) < 0) {
                        upEnd = d;
                        upper.setExpeEndDate(upEnd);
                        needUpper = true;
                    }
                }
            }
            if (needUpper) {
                // 计算工期。。。
                upper.setExpeDuration((int) DateUtils.getDaysBetween(upStart, upEnd));
                updatePlan.add(upper);
            }
            cur = upper;
            ori = oriUpper;
            if (!StringUtils.isEmpty(cur.getPkParent())) {
                upper = mapper.getById(cur.getPkParent());
                if (upper != null) {
                    oriUpper = (ProjectPlanVO) upper.clone();
                }
            } else {
                break;
            }
        } while (needUpper && upper != null);
    }

    private void fetchUpdateForInsert(ProjectPlanVO cur, ProjectPlanVO upper, List<ProjectPlanVO> updatePlan) {
        boolean needUpper = false;
        needUpper = false;
        Date start = cur.getExpeStartDate();
        Date end = cur.getExpeEndDate();
        //  插入时直接开始时间和上级开始时间比较就好，当然还需要考虑上级只有一个下级的情况
        ProjectPlanVO origUpper = (ProjectPlanVO) upper.clone();
        Date upStart = upper.getExpeStartDate();
        Date upEnd = upper.getExpeEndDate();
        if (start.compareTo(upStart) < 0 || parent.getChildCount() == 1) {
            upStart = start;
            upper.setExpeStartDate(upStart);
            needUpper = true;
        }
        if (end.compareTo(upEnd) > 0 || parent.getChildCount() == 1) {
            upEnd = end;
            upper.setExpeEndDate(upEnd);
            needUpper = true;
        }
        if (needUpper) {
            // 计算工期。。。
            upper.setExpeDuration((int) DateUtils.getDaysBetween(upStart, upEnd));
            updatePlan.add(upper);
        }
        cur = upper;
        if (!StringUtils.isEmpty(cur.getPkParent())) {
            upper = mapper.getById(cur.getPkParent());
            if (needUpper && upper != null) {
                // 被插入的计划的上级，相当于修改了上级，调用update的调整日期方法
                fetchUpdateForUpdate(cur, upper, origUpper, (ProjectPlanVO) upper.clone(), updatePlan);
            }
        }
    }
}
